#include "DealProtocol.h"
#include <windows.h>
/*!\class DealProtocol
Class for the protocol management (in this function Critical Section are used).*/
DealProtocol::DealProtocol(GraphicEngine *Engine,SoundSystem *sound, 
						   SocketComm *pSocket, LedDriver *myLed): DealProtType (Engine,sound,pSocket,myLed)
{
	FILE *protFile;
	dllCont=0;
	protFile = fopen("Protocols.txt","r");
	if (protFile == NULL)
	{
		cout<<"Error!!! Protocols.txt not found."<<endl;
		MessageBox(0,L"Error!!! Protocols.txt not found.",L"Error",0);
		exit(1);
	}
	else
	{
		while(!feof(protFile))
		{
			fscanf(protFile,"%s",&Protocolli[dllCont].protocolName);
			fscanf(protFile,"%s",&Protocolli[dllCont].dllProtocol);
			dllCont++;
		}
		fclose(protFile);
	}
	//Per dll
	hLib = NULL;
	pGetNewProtocol = NULL;
	pReleaseProtocol = NULL;

	AEngine = Engine;
	MainAudio = sound;
	MainSocket = pSocket;
	Stimuli = myLed;
	pProtocol = NULL;
	ghMutex = CreateMutex(NULL,FALSE,NULL);
	if (ghMutex == NULL)
		cout<<"Error in mutex creation"<<endl;
}

DealProtocol::~DealProtocol(void)
{
	::FreeLibrary(hLib);
}

bool DealProtocol::runProtocol(char *protocollo, bool startup = false)
{
	int i;
	for (i=1; i<dllCont; i++)
	{
		if (strcmp(protocollo,Protocolli[i-1].protocolName)==0)
		{
			size_t convertedChars=0;
			wchar_t w_protocol[255];
			mbstowcs_s(&convertedChars,w_protocol,strlen(Protocolli[i-1].dllProtocol)+1,Protocolli[i-1].dllProtocol,strlen(Protocolli[i-1].dllProtocol));
			if (hLib == NULL) hLib = ::LoadLibrary(w_protocol);
			cout<<"****** "<<Protocolli[i-1].protocolName<<" PROTOCOL ******"<<endl;
			break;
		}
	}
	if (i>=dllCont)
	{
		cout<<"Selected protocol doesn't exist!!! (Parameter #2)"<<endl;
		cout<<"AEnima will be closed"<<endl;
		MessageBox(0,L"Selected protocol doesn't exist \nCheck Command Line Parameter #2",L"Error",0);
		pProtocol = NULL;
		hLib=0;
		return true;
	}
	if ((hLib !=NULL) )//&& (hLib!=unused))
	{
		pGetNewProtocol = (hGetNewProtocol) ::GetProcAddress(hLib, "GetNewProtocol");
		pReleaseProtocol = (hReleaseProtocol) ::GetProcAddress(hLib, "ReleaseProtocol");
//		pEvalProt = (hEvalProt) ::GetProcAddress(hLib,"EvalProt");
		if (pGetNewProtocol == NULL)
		{
			::FreeLibrary(hLib);
			cout<<"Error in GetNewProtocol pointer"<<endl;
			return true;;
		}
		else if (pGetNewProtocol != NULL)
		{
			pProtocol = pGetNewProtocol(AEngine, MainAudio, MainSocket, Stimuli, startup, this);
			return false;
		}
	}
	else 
	{
		cout<<Protocolli[i].dllProtocol<<" doesn't exist"<<endl;
		MessageBox(0,L"The dll file doesn't exist.\nCheck if Protocols.txt is correct.",L"Error",0);
		return true;
	}
}

void DealProtocol::changeProtocol(char *name, bool startup = true)
{
	int i;
	char protocollo[256];

	WaitForSingleObject(ghMutex,INFINITE);
	if (name!=NULL)
		strcpy(protocollo,name);
	pProtocol->StopProt(false);
	Stimuli->Stop();
	if (pReleaseProtocol!=NULL)
	{
		pReleaseProtocol(pProtocol); //Delete pProtocol
		//if (hLib!=NULL)
			//::FreeLibrary(hLib);
		hLib=NULL;
		pProtocol=NULL;
	}
	if (name==NULL)
		exit(0);
	for (i=0; i<dllCont; i++)
	{
		if (strcmp(protocollo,Protocolli[i].protocolName)==0)
		{
			if (hLib == NULL) 
				runProtocol(Protocolli[i].protocolName, startup);
			break;
		}
	}
	if (i>=dllCont)
	{
		cout<<"Selected protocol doesn't exist!!! (Parameter #2)"<<endl;
		cout<<"AEnima will be closed"<<endl;
		MessageBox(0,L"Selected protocol doesn't exist \nCheck Command Line Parameter #2",L"Error",0);
		pProtocol = NULL;
		hLib=0;
		exit(-1);
	}
	
	if (pProtocol!=NULL)
	{
		pProtocol->StartProt(false);
		AEngine->fader->fadeIn(1000);
	}
	ReleaseMutex(ghMutex);
}	

void DealProtocol::EvalProt(void)
{
	int Result;
	if (ghMutex!=NULL)
	{	
		Result = WaitForSingleObject(ghMutex,0);
		if (Result==WAIT_OBJECT_0)
		{
		    if (pProtocol != NULL)					
				pProtocol->EvalProt();
			ReleaseMutex(ghMutex);
		}
	
	}
}

bool DealProtocol::StartProt(void)
{
	bool risp;
	if (pProtocol == NULL)
		return 0;
	risp = pProtocol->StartProt();
	return risp;
}

bool DealProtocol::StopProt(void)
{
	bool risp;
	if (pProtocol == NULL)
		return 0;
	risp = pProtocol->StopProt();
	return risp;
}

void DealProtocol::OnProtocolEvent()
{
	if(WaitForSingleObject(ghMutex,0)==WAIT_OBJECT_0)
		if (pProtocol != NULL)	pProtocol->OnProtocolEvent();
	ReleaseMutex(ghMutex);
}

void DealProtocol::OnSocketEvent(BCIMessage *SocketMsg)
{
	if(WaitForSingleObject(ghMutex,0)==WAIT_OBJECT_0)
		if ((pProtocol != NULL) && (SocketMsg != NULL))pProtocol->OnSocketEvent(SocketMsg);
	ReleaseMutex(ghMutex);
}

void DealProtocol::RunIntoWhile(void)
{
	int Result;
	if (ghMutex!=NULL)
	{	
		Result = WaitForSingleObject(ghMutex,0);
		if (Result==WAIT_OBJECT_0)
		{
		    if (pProtocol != NULL)					
				pProtocol->RunIntoWhile();
			ReleaseMutex(ghMutex);
		}
	
	}
}